home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
17 Bit Software 6: Level 6
/
17 Bit - Level 6 (1998)(Epic Marketing)[!].iso
/
quartz
/
q0429.dms
/
q0429.adf
/
libray
/
libobj
/
sphere.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-08-08
|
5KB
|
243 lines
/*
* sphere.c
*
* Copyright (C) 1989, 1991, Craig E. Kolb
* All rights reserved.
*
* This software may be freely copied, modified, and redistributed
* provided that this copyright notice is preserved on all copies.
*
* You may not distribute this software, in whole or in part, as part of
* any commercial product without the express consent of the authors.
*
* There is no warranty or other guarantee of fitness of this software
* for any purpose. It is provided solely "as is".
*
* $Id: sphere.c,v 4.0 91/07/17 14:39:17 kolb Exp Locker: kolb $
*
* $Log: sphere.c,v $
* Revision 4.0 91/07/17 14:39:17 kolb
* Initial version.
*
*/
#include "geom.h"
#include "sphere.h"
static Methods *iSphereMethods = NULL;
static char sphereName[] = "sphere";
unsigned long SphTests, SphHits;
/*
* Create & return reference to a sphere.
*/
Sphere *
SphereCreate(r, pos)
Float r;
Vector *pos;
{
Sphere *sphere;
if (r < EPSILON) {
RLerror(RL_WARN, "Degenerate sphere.\n");
return (Sphere *)NULL;
}
sphere = (Sphere *)share_malloc(sizeof(Sphere));
/*
* sphere->rsq holds the square of the radius.
*/
sphere->r = r;
sphere->rsq = r*r;
sphere->x = pos->x;
sphere->y = pos->y;
sphere->z = pos->z;
return sphere;
}
Methods *
SphereMethods()
{
if (iSphereMethods == (Methods *)NULL) {
iSphereMethods = MethodsCreate();
iSphereMethods->create = (GeomCreateFunc *)SphereCreate;
iSphereMethods->methods = SphereMethods;
iSphereMethods->name = SphereName;
iSphereMethods->intersect = SphereIntersect;
iSphereMethods->normal = SphereNormal;
iSphereMethods->uv = SphereUV;
iSphereMethods->enter = SphereEnter;
iSphereMethods->bounds = SphereBounds;
iSphereMethods->stats = SphereStats;
iSphereMethods->checkbounds = TRUE;
iSphereMethods->closed = TRUE;
}
return iSphereMethods;
}
/*
* Ray/sphere intersection test.
*/
int
SphereIntersect(sph, ray, mindist, maxdist)
Sphere *sph;
Ray *ray;
Float mindist, *maxdist;
{
Float xadj, yadj, zadj;
Float b, t, s;
SphTests++;
/*
* Translate ray origin to object space and negate everything.
* (Thus, we translate the sphere into ray space, which saves
* us a couple of negations below.)
*/
xadj = sph->x - ray->pos.x;
yadj = sph->y - ray->pos.y;
zadj = sph->z - ray->pos.z;
/*
* Solve quadratic equation.
*/
b = xadj * ray->dir.x + yadj * ray->dir.y + zadj * ray->dir.z;
t = b * b - xadj * xadj - yadj * yadj - zadj * zadj + sph->rsq;
if (t < 0.)
return FALSE;
t = (Float)sqrt((double)t);
s = b - t;
if (s > mindist) {
if (s < *maxdist) {
*maxdist = s;
SphHits++;
return TRUE;
}
return FALSE;
}
s = b + t;
if (s > mindist && s < *maxdist) {
*maxdist = s;
SphHits++;
return TRUE;
}
return FALSE;
}
/*
* Compute normal to sphere at pos
*/
int
SphereNormal(sphere, pos, nrm, gnrm)
Sphere *sphere;
Vector *pos, *nrm, *gnrm;
{
nrm->x = (pos->x - sphere->x) / sphere->r;
nrm->y = (pos->y - sphere->y) / sphere->r;
nrm->z = (pos->z - sphere->z) / sphere->r;
*gnrm = *nrm;
return FALSE;
}
/*
* Determine if ray enters (TRUE) or leaves (FALSE) sphere at pos
*/
int
SphereEnter(sphere, ray, mind, hitd)
Sphere *sphere;
Ray *ray;
Float mind, hitd;
{
Vector pos;
VecAddScaled(ray->pos, mind, ray->dir, &pos);
pos.x -= sphere->x;
pos.y -= sphere->y;
pos.z -= sphere->z;
return dotp(&pos, &pos) > sphere->rsq;
}
/*ARGSUSED*/
void
SphereUV(sphere, pos, norm, uv, dpdu, dpdv)
Sphere *sphere;
Vector *pos, *norm, *dpdu, *dpdv;
Vec2d *uv;
{
Float phi, theta;
Vector realnorm;
realnorm.x = pos->x - sphere->x;
realnorm.y = pos->y - sphere->y;
realnorm.z = pos->z - sphere->z;
VecNormalize( &realnorm );
if (realnorm.z > 1.) /* roundoff */
phi = PI;
else if (realnorm.z < -1.)
phi = 0;
else
phi = acos(-realnorm.z);
uv->v = phi / PI;
if (fabs(uv->v) < EPSILON || equal(uv->v, 1.))
uv->u = 0.;
else {
theta = realnorm.x / sin(phi);
if (theta > 1.)
theta = 0.;
else if (theta < -1.)
theta = 0.5;
else
theta = acos(theta) / TWOPI;
if (realnorm.y > 0)
uv->u = theta;
else
uv->u = 1 - theta;
}
if (dpdu != (Vector *)0) {
dpdu->x = -realnorm.y;
dpdu->y = realnorm.x;
dpdu->z = 0.;
(void)VecNormalize(dpdu);
(void)VecNormCross(&realnorm, dpdu, dpdv);
}
}
void
SphereBounds(s, bounds)
Sphere *s;
Float bounds[2][3];
{
bounds[LOW][X] = s->x - s->r;
bounds[HIGH][X] = s->x + s->r;
bounds[LOW][Y] = s->y - s->r;
bounds[HIGH][Y] = s->y + s->r;
bounds[LOW][Z] = s->z - s->r;
bounds[HIGH][Z] = s->z + s->r;
}
char *
SphereName()
{
return sphereName;
}
void
SphereStats(tests, hits)
unsigned long *tests, *hits;
{
*tests = SphTests;
*hits = SphHits;
}
void
SphereMethodRegister(meth)
UserMethodType meth;
{
if (iSphereMethods)
iSphereMethods->user = meth;
}